type InputEx

Public:
    as uinteger maxlength, y, x, cretval
    as ubyte password, cancel, numonly
    as double timeout

    _print_cb as sub( as uinteger, as uinteger, as string, as any ptr )
    _print_cb_data as any ptr
    _callback as function( as uinteger ) as integer

    declare Function get( x as uinteger = Pos(), y as uinteger = Csrlin() ) as string
    declare constructor()

Private:
    as string temp

end type

declare sub _def_print( x as uinteger, y as uinteger, _
            data_ as string, _nu as any ptr = NULL )

declare sub _def_gfx_print( x as uinteger, y as uinteger, _
            data_ as string, _color as any ptr = NULL )

constructor InputEx

    this.maxlength = 255
        this.password = 0
        this.cancel = 1
    this.numonly = 0
    this.timeout = 0
    this._print_cb = @_def_print
    this._print_cb_data = NULL

end constructor

function InputEx.get( x as uinteger = Pos(), y as uinteger = Csrlin() ) as string

    Dim As String mykey, blank, display
    Dim As Double mytimer, timerout

    while inkey <> ""
    wend

    If y < 1 Or x < 1 Then
        Return ""
    else
        this.y = y
        this.x = x
    End If

    If timeout > 0 Then
        timerout = Timer + timeout
    else
        this.temp = ""
    end if

    mytimer = Timer +.5

    Do

        mykey = Inkey

        If Len(mykey) > 0 Then
            Select Case mykey
            Case ""  '' This shouldn't happen

            Case Chr(8)  '' Backspace key
                If Len(temp) = 1 Then
                    blank = Space(Len(this.temp)+1)
                    this.temp = ""
                Else
                    If Len(this.temp) > 0 Then
                        blank = Space(Len(this.temp)+1)
                        this.temp = Left(this.temp, Len(this.temp) - 1)
                    End If
                End If

                this._print_cb(x,y,blank,this._print_cb_data)

            Case Chr(27) '' Escape key, our cancel key
                If this.cancel = 0 Then
                    this.temp = Chr(27)
                    Exit Do
                End If

            Case Else  '' This is where the magic happens
                If this.numonly > 0 Then
                '' do numeric only input first
                    If mykey[0]<48 Or mykey[0] > 57 Then
                        If mykey[0] <> 13 Then
                            If mykey[0] <> 46 Then
                                mykey = ""
                            End If
                        End If
                    else
                        if mykey[0] <> 46 then
                            if this._callback <> 0 then
                                cretval = this._callback( mykey[0] )
                                if cretval > 0 then exit do
                                if cretval = 0 then
                                    this.temp += mykey
                                else
                                    mykey = ""
                                end if
                            else
                                this.temp += mykey
                            end if
                        end if
                    End If
                else
                    If mykey[0] > 31 And mykey[0] < 255 Then
                        If this.timeout > 0 Then timerout = Timer + this.timeout
                        if this._callback <> 0 then
                            cretval = this._callback( mykey[0] )
                            if cretval > 0 then exit do
                            if cretval = 0 then
                                this.temp += mykey
                            else
                                mykey = ""
                            end if
                        else
                            this.temp += mykey
                        end if

                    End If
                end if

            End Select

            '' time to refresh display

            Select Case this.password

            Case 0 '' Not password entry
                display = this.temp

            Case Else '' Password entry
                display = String(Len(this.temp), "*")

            End Select

        End If

        Sleep 50


        If Timer > mytimer Then
            this._print_cb(x,y,display & "_",this._print_cb_data)
            mytimer = Timer + .5
        Else
            this._print_cb(x,y,display & " ",this._print_cb_data)
        End If

        If timerout > 0 Then
            If Timer > timerout Then Exit Do
        End If

        sleep 10

    Loop Until mykey = Chr(13) Or Len(this.temp) = maxlength

    this._print_cb(x,y,display & " ",this._print_cb_data)

    Return this.temp

End Function

sub _def_print( x as uinteger, y as uinteger, data_ as string, _nu as any ptr = NULL )

    locate y, x
    print data_

end sub

sub _def_gfx_print( x as uinteger, y as uinteger, data_ as string, _color as any ptr = NULL )

    if _color <> 0 then
        draw string (x,y), data_,*(cast(integer ptr, _color))
    else
        draw string (x,y), data_
    end if

end sub
